package net.homeip.jcperera.nu.core.utils;

import java.io.Serializable;

import net.homeip.jcperera.nu.core.CoreBase;

/**
 * <p>
 * A bunch of reflection-based functions to get information about the execution environment
 * </p>
 * 
 * @name Java Reflection Utility class
 * @author julio.c.perera@gmail.com
 * @application nu
 * @since 0.1.0.0@
 */

public class ReflectionUtils extends CoreBase implements Serializable
{
    // Required to implement Serializable interface
    private static final long  serialVersionUID = 4818561988674211875L;

    // CoreBase properties, for easy use from other components, as well as logging
    public static final int    runtimeLevel     = 0;
    public static final String moduleName       = "core";
    public static final String componentName    = "nu_core_utils_reflection";

    public static StackTraceElement getCallerStackTraceElement(int levelsUp)
    {
        StackTraceElement result = null;
        try
        {
            if (levelsUp > 0) result = new Throwable().fillInStackTrace().getStackTrace()[levelsUp + 1];
        }
        catch (Exception e)
        {
        }
        return result;
    }

    public static String getClassNameForCaller(int levelsUp)
    {
        String callingClassName = "";
        StackTraceElement ste = null;
        try
        {
            ste = getCallerStackTraceElement(levelsUp + 1);
            if (ste != null) callingClassName = ste.getClassName();
        }
        catch (Exception e)
        {
        }
        return callingClassName;
    }

    public static Class<?> getClassFromClassName(String className)
    {
        Class<?> result = null;
        if (className != null)
        {
            try
            {
                result = Class.forName(className);
            }
            catch (ClassNotFoundException e)
            {
                result = null;
            }
        }
        return result;
    }

    public static Class<?> getClassForCaller(int levelsUp)
    {
        return getClassFromClassName(getClassNameForCaller(levelsUp + 1));
    }

    public static boolean isSubClassOf(Class<?> baseClass, Class<?> derivateClass)
    {
        return baseClass != null && derivateClass != null && baseClass.isAssignableFrom(derivateClass);
    }

    public static boolean isInterfaceImplementedInClass(Class<?> interfaceClass, Class<?> implementedClass)
    {
        return interfaceClass != null && implementedClass != null && interfaceClass.isInterface()
                && interfaceClass.isAssignableFrom(implementedClass);
    }

    public static boolean isInterfaceImplementedInCaller(Class<?> interfaceClass, int levelsUp)
    {
        Class<?> callerClass = getClassForCaller(levelsUp + 1);
        return isInterfaceImplementedInClass(interfaceClass, callerClass);
    }

    public static boolean isCallerSubClassOf(Class<?> baseClass, int levelsUp)
    {
        Class<?> callerClass = getClassForCaller(levelsUp + 1);
        return isSubClassOf(baseClass, callerClass);
    }
}
